一覧に戻る

Next.jsで作ったnext exportしたアプリをNginxで静的配信するための設定

#nginx#フロントエンド#React#Next.js

TL;DR

  • next exportは他のウェブフレームワークと違い、単一のhtmlではなくpages単位でhtmlを書き出す
  • そのため、一般的なSPA向けのサーバー設定では、ブラウザの更新時に404が発生してしまう
  • これを回避するには、/というパスへのリクエスト時に/index.html/hogeなら/hoge.htmlを探しに行く設定がwebサーバーに必要。下記はNginxの設定例。
location / {
    root /hoge/fuga/html;
    index index.html;
    try_files $uri $uri.html $uri/ /404.html;
}

はじめに

これまでは一番経験があり安定して開発できる技術としてVue2を使ってきたのですが、EoLも見えてきてそろそろ乗り換え…ということで、Next.jsを使い始めました。このとき静的にアプリケーションを配信するためのコマンドnext exportが、これまで触ってきたSPA(たとえばVue)の挙動と違い、そのためwebサーバーの設定で少し困ったので、メモしておきます。

Vueのビルドと違うところ

Vueの場合index.htmlはひとつですが、next exportpagesに配置されているコンポーネントの数だけhtmlが作成されます。SSG用のコマンドなので事前に全ページのHTMLを作成しておく、という思想なのでしょう。

たとえば

pages
├── _app.tsx
├── sample.tsx
└── index.tsx

こんな構造だと、next exportの結果は

dist
├── 404.html
├── _next
├── sample.html
└── index.html

こんな感じになるはずです。

困ったこと

上記でも、ローカルで開発している限りは、特に困ることがありません。しかしこのビルド結果をVueだとかと同じ感覚でデプロイすると(=単なるwebサーバーでの配信+index.htmlへのフォールバック)、ページリロード時に404となったり、トップページが表示されたりと、期待した挙動になりません。

期待した挙動にならない理屈

  1. CSRで/sampleを表示しているとする
  2. 更新すると、webサーバーはsampleというファイルを探しに行く(が、存在しない)
  3. 存在しないのでindex.htmlにフォールバックする(が、ページが/sampleとしてレンダリングされない!

2まではVueのルーティングでも起こる問題ですが、3はNext.jsで発生する問題です。 Next.jsでは、/sampleを更新する際は/sample.htmlを見に行かせる設定が必要となります。

Nginxの設定

下記のように設定することで、/hogeというURLをリクエストして/hogeが存在しなければ、/hoge.htmlを探しに行かせることができます。また、/へのリクエストは/index.htmlに流す、という設定も必要です。下記が設定ファイルの例です(冒頭と同じ)。

location / {
    root /hoge/fuga/html;
    index index.html;
    try_files $uri $uri.html $uri/ /404.html;
}

終わりに

インターネッツを探しても、あんまり記事が見つからなかったのですが、next exportをNginxで運用…というのはあんまりやるべきじゃないのでしょうか? それとももっと良い方法がある?webサーバー+CSRがもう流行っていない?CRAを使うべき? 知見のある方はコメント頂けるとうれしいです。。。